// Global variables
let network = null;
let currentNodes = new vis.DataSet();
let currentEdges = new vis.DataSet();

// Color schemes for nodes based on their type
const nodeColorScheme = {
    'class': '#4ECDC4',      // Teal for Classes
    'directory': '#FFD93D',   // Gold for Directories
    'file': '#667eea',        // Blue for Files
    'function': '#96CEB4',    // Green for Functions
    'default': '#95A5A6'      // Default gray
};

// Color schemes for edges based on type
const edgeColorScheme = {
    'contains': '#10b981',    // Green - containment relationship
    'imports': '#667eea',     // Blue - import dependency
    'inherits': '#ef4444',    // Red - inheritance relationship
    'invokes': '#f59e0b',     // Orange - method invocation
    'dependency': '#848484',  // Gray - generic dependency
    'default': '#848484'      // Default gray
};

// Function to determine node color based on its type
function getNodeColor(nodeType, isCenter = false) {
    // No special color for center node - use type-based color
    const type = (nodeType || 'default').toLowerCase();
    return nodeColorScheme[type] || nodeColorScheme.default;
}

// Function to determine edge color based on its type
function getEdgeColor(edgeType) {
    const type = (edgeType || 'default').toLowerCase();
    return edgeColorScheme[type] || edgeColorScheme.default;
}

// Initialize the application
document.addEventListener('DOMContentLoaded', function() {
    console.log('Initializing application...');
    initializeGraph();
    loadStats();
    setupEventListeners();
    console.log('Application initialized');
});

// Initialize the vis.js network graph
function initializeGraph() {
    const container = document.getElementById('graph');

    const data = {
        nodes: currentNodes,
        edges: currentEdges
    };

    const options = {
        nodes: {
            shape: 'dot',
            scaling: {
                min: 10,
                max: 50,
                label: {
                    min: 8,
                    max: 20
                }
            },
            font: {
                size: 12,
                face: 'Arial'
            }
        },
        edges: {
            arrows: {
                to: {
                    enabled: true,
                    scaleFactor: 0.5
                }
            },
            smooth: {
                type: 'cubicBezier'
            },
            color: {
                color: '#848484',
                highlight: '#667eea'
            }
        },
        physics: {
            forceAtlas2Based: {
                gravitationalConstant: -26,
                centralGravity: 0.005,
                springLength: 100,
                springConstant: 0.08
            },
            maxVelocity: 146,
            solver: 'forceAtlas2Based',
            timestep: 0.35,
            stabilization: {
                iterations: 150
            }
        },
        interaction: {
            hover: true,
            tooltipDelay: 200,
            hideEdgesOnDrag: true
        }
    };

    network = new vis.Network(container, data, options);

    // Handle node selection
    network.on('selectNode', function(params) {
        if (params.nodes.length > 0) {
            const nodeId = params.nodes[0];
            showNodeInfo(nodeId);
        }
    });

    // Handle edge selection
    network.on('selectEdge', function(params) {
        if (params.edges.length > 0) {
            const edgeId = params.edges[0];
            showEdgeInfo(edgeId);
        }
    });

    // Handle double click to expand
    network.on('doubleClick', function(params) {
        if (params.nodes.length > 0) {
            const nodeId = params.nodes[0];
            expandNode(nodeId);
        }
    });
}

// Load graph statistics
async function loadStats() {
    try {
        const response = await axios.get('/api/stats');
        const stats = response.data;

        document.getElementById('stats').innerHTML = `
            <strong>Total Nodes:</strong> ${stats.total_nodes} |
            <strong>Total Edges:</strong> ${stats.total_edges} |
            <strong>Average Degree:</strong> ${stats.avg_degree.toFixed(2)}
        `;

        // Display top nodes
        const topNodesHtml = stats.top_nodes.map(node => `
            <div class="node-item" onclick="loadNodeGraph('${node.id}')">
                <div class="node-name">${node.label}</div>
                <div class="node-stats">
                    Degree: ${node.degree} (In: ${node.in_degree}, Out: ${node.out_degree})
                </div>
            </div>
        `).join('');

        document.getElementById('topNodes').innerHTML = topNodesHtml;
    } catch (error) {
        console.error('Error loading stats:', error);
    }
}

// Setup event listeners
function setupEventListeners() {
    // Search functionality
    const searchBtn = document.getElementById('searchBtn');
    const searchInput = document.getElementById('searchInput');
    const clearBtn = document.getElementById('clearBtn');

    if (!searchBtn || !searchInput || !clearBtn) {
        console.error('Search elements not found!', {searchBtn, searchInput, clearBtn});
        return;
    }

    searchBtn.addEventListener('click', function() {
        console.log('Search button clicked');
        performSearch();
    });

    searchInput.addEventListener('keypress', function(e) {
        if (e.key === 'Enter') {
            console.log('Enter key pressed in search input');
            performSearch();
        }
    });

    // Clear button
    clearBtn.addEventListener('click', function() {
        console.log('Clear button clicked');
        document.getElementById('searchInput').value = '';
        document.getElementById('searchResults').innerHTML = '';
    });

    // Reset view button
    document.getElementById('resetView').addEventListener('click', function() {
        if (network) {
            network.fit();
        }
    });
}

// Perform search
async function performSearch() {
    const query = document.getElementById('searchInput').value;
    if (!query) {
        console.log('Search query is empty');
        return;
    }

    console.log('Searching for:', query);

    try {
        const response = await axios.get('/api/search', {
            params: { q: query }
        });

        console.log('Search response:', response.data);
        const results = response.data;

        if (results.length === 0) {
            document.getElementById('searchResults').innerHTML = '<p>No results found</p>';
            return;
        }

        const resultsHtml = results.map(node => `
            <div class="node-item" onclick="loadNodeGraph('${node.id}')">
                <div class="node-name">${node.label}</div>
                <div class="node-stats">
                    Degree: ${node.degree} (In: ${node.in_degree}, Out: ${node.out_degree})
                </div>
            </div>
        `).join('');

        document.getElementById('searchResults').innerHTML = resultsHtml;
        console.log('Search results displayed');
    } catch (error) {
        console.error('Error searching:', error);
        console.error('Error details:', error.response || error.message);
        document.getElementById('searchResults').innerHTML = `<p>Error performing search: ${error.message}</p>`;
    }
}

// Load node graph
async function loadNodeGraph(nodeId) {
    const maxDegree = document.getElementById('maxDegree').value;
    const depth = document.getElementById('depth').value;

    try {
        const params = { depth: parseInt(depth) };
        if (maxDegree) {
            params.max_degree = parseInt(maxDegree);
        }

        const response = await axios.get(`/api/graph/${encodeURIComponent(nodeId)}`, {
            params: params
        });

        const graphData = response.data;

        // Clear existing data
        currentNodes.clear();
        currentEdges.clear();

        // Add nodes
        const nodes = graphData.nodes.map(node => ({
            id: node.id,
            label: node.label,
            title: `${node.id}\nType: ${node.type}\nDegree: ${node.degree}\nIn: ${node.in_degree}, Out: ${node.out_degree}`,
            value: node.degree,
            color: getNodeColor(node.type, node.id === graphData.center)
        }));

        currentNodes.add(nodes);

        // Add edges
        const edges = graphData.edges.map(edge => ({
            from: edge.source,
            to: edge.target,
            title: edge.type,
            label: edge.type,
            color: {
                color: getEdgeColor(edge.type),
                highlight: '#667eea'
            },
            data: edge  // Store the full edge data for later use
        }));

        currentEdges.add(edges);

        // Fit network to show all nodes
        setTimeout(() => {
            network.fit();
        }, 500);

        // Show info for center node
        showNodeInfo(graphData.center);
    } catch (error) {
        console.error('Error loading graph:', error);
        alert('Error loading graph data');
    }
}

// Expand a node
async function expandNode(nodeId) {
    try {
        const response = await axios.get(`/api/expand/${encodeURIComponent(nodeId)}`);
        const data = response.data;

        // Add new nodes (avoid duplicates)
        const existingNodeIds = currentNodes.getIds();
        const newNodes = data.nodes.filter(node => !existingNodeIds.includes(node.id));

        if (newNodes.length > 0) {
            const nodes = newNodes.map(node => ({
                id: node.id,
                label: node.label,
                title: `${node.id}\nType: ${node.type}\nDegree: ${node.degree}\nIn: ${node.in_degree}, Out: ${node.out_degree}`,
                value: node.degree,
                color: getNodeColor(node.type, node.group === 1)
            }));

            currentNodes.add(nodes);
        }

        // Add new edges (avoid duplicates)
        const newEdges = [];
        data.edges.forEach(edge => {
            const edgeId = `${edge.source}-${edge.target}`;
            const existingEdge = currentEdges.get({
                filter: function(item) {
                    return item.from === edge.source && item.to === edge.target;
                }
            });

            if (existingEdge.length === 0) {
                newEdges.push({
                    from: edge.source,
                    to: edge.target,
                    title: edge.type,
                    label: edge.type,
                    color: {
                        color: getEdgeColor(edge.type),
                        highlight: '#667eea'
                    },
                    data: edge  // Store the full edge data for later use
                });
            }
        });

        if (newEdges.length > 0) {
            currentEdges.add(newEdges);
        }

        // Update node color to indicate it has been expanded
        currentNodes.update({
            id: nodeId,
            color: '#10b981'
        });
    } catch (error) {
        console.error('Error expanding node:', error);
    }
}

// Show edge information
function showEdgeInfo(edgeId) {
    try {
        const edge = currentEdges.get(edgeId);
        if (!edge) {
            console.error('Edge not found:', edgeId);
            return;
        }

        const edgeData = edge.data || {};
        const sourceNode = currentNodes.get(edge.from);
        const targetNode = currentNodes.get(edge.to);

        const infoHtml = `
            <div class="info-section">
                <h4>Edge Information</h4>
                <p><strong>Type:</strong> ${edge.title || edge.label || 'Unknown'}</p>
            </div>

            <div class="info-section">
                <h4>Source Node</h4>
                <p style="word-break: break-all; cursor: pointer; color: #667eea;" onclick="showNodeInfo('${edge.from}')">
                    ${sourceNode ? sourceNode.label : edge.from}
                </p>
            </div>

            <div class="info-section">
                <h4>Target Node</h4>
                <p style="word-break: break-all; cursor: pointer; color: #667eea;" onclick="showNodeInfo('${edge.to}')">
                    ${targetNode ? targetNode.label : edge.to}
                </p>
            </div>

            ${edgeData.properties ? `
            <div class="info-section">
                <h4>Edge Properties</h4>
                <ul class="info-list">
                    ${Object.entries(edgeData.properties).map(([key, value]) =>
                        `<li><strong>${key}:</strong> ${value}</li>`
                    ).join('')}
                </ul>
            </div>
            ` : ''}

            <div class="info-section">
                <button onclick="showNodeInfo('${edge.from}')">View Source Node</button>
                <button onclick="showNodeInfo('${edge.to}')">View Target Node</button>
            </div>
        `;

        document.getElementById('nodeInfo').innerHTML = infoHtml;
    } catch (error) {
        console.error('Error showing edge info:', error);
        document.getElementById('nodeInfo').innerHTML = '<p>Error loading edge information</p>';
    }
}

// Show node information
async function showNodeInfo(nodeId) {
    try {
        const response = await axios.get(`/api/node/${encodeURIComponent(nodeId)}`);
        const info = response.data;

        const infoHtml = `
            <div class="info-section">
                <h4>Node ID</h4>
                <p style="word-break: break-all;">${info.id}</p>
            </div>

            <div class="info-section">
                <h4>Degree Statistics</h4>
                <p>Total Degree: <span class="badge">${info.total_degree}</span></p>
                <p>In-Degree: <span class="badge">${info.in_degree}</span></p>
                <p>Out-Degree: <span class="badge">${info.out_degree}</span></p>
            </div>

            <div class="info-section">
                <h4>Dependencies (Incoming)</h4>
                <ul class="info-list">
                    ${info.predecessors.slice(0, 10).map(pred =>
                        `<li onclick="loadNodeGraph('${pred}')" style="cursor: pointer;">${pred.split('/').pop()}</li>`
                    ).join('')}
                    ${info.predecessors.length > 10 ? `<li>... and ${info.predecessors.length - 10} more</li>` : ''}
                </ul>
            </div>

            <div class="info-section">
                <h4>Depends On (Outgoing)</h4>
                <ul class="info-list">
                    ${info.successors.slice(0, 10).map(succ =>
                        `<li onclick="loadNodeGraph('${succ}')" style="cursor: pointer;">${succ.split('/').pop()}</li>`
                    ).join('')}
                    ${info.successors.length > 10 ? `<li>... and ${info.successors.length - 10} more</li>` : ''}
                </ul>
            </div>

            <div class="info-section">
                <button onclick="expandNode('${nodeId}')">Expand Node</button>
                <button onclick="loadNodeGraph('${nodeId}')">Center on Node</button>
            </div>
        `;

        document.getElementById('nodeInfo').innerHTML = infoHtml;
    } catch (error) {
        console.error('Error loading node info:', error);
        document.getElementById('nodeInfo').innerHTML = '<p>Error loading node information</p>';
    }
}

// Make functions globally accessible
window.loadNodeGraph = loadNodeGraph;
window.expandNode = expandNode;
window.showNodeInfo = showNodeInfo;
window.showEdgeInfo = showEdgeInfo;